home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / bench / bench.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-24  |  13.3 KB  |  496 lines

  1. /*
  2.  * A standard harness with which to benchmark programs.
  3.  * This sets up statistics stuff, then forks and execs a
  4.  * program to benchmark.  When the program completes, its
  5.  * resource usage is recorded, as well as other filesystem
  6.  * related statistics.
  7.  *
  8.  * The programs output goes to standard out, while the
  9.  * statistics taken go to error output or another file.
  10.  */
  11.  
  12. #include "sprite.h"
  13. #include "status.h"
  14. #include "sys/ioctl.h"
  15. #include "sys/file.h"
  16. #include "fs.h"
  17. #include "fsCmd.h"
  18. #include "sysStats.h"
  19. #include "proc.h"
  20. #include "vm.h"
  21. #include "kernel/sched.h"
  22. #include "kernel/fsStat.h"
  23. #include "kernel/vm.h"
  24. #include "kernel/net.h"
  25. #include "option.h"
  26. #include "sig.h"
  27. #include "signal.h"
  28. #include "stdio.h"
  29. #ifdef spur
  30. #include "ccMachStat.h"
  31. #endif
  32. Boolean flushCache = FALSE;
  33. Boolean clean = FALSE;
  34. Boolean exec = FALSE;
  35. Boolean histogram = FALSE;
  36. int numClients = -1;            /* For multi-program synchronization,
  37.                      * this is the number of slaves with
  38.                      * which to synchronize */
  39. Boolean slave = FALSE;
  40. char *outFile = "bench.out";
  41. extern char *pdev;
  42. Boolean    dontSyncCache = FALSE;
  43. Boolean    useSignals = FALSE;
  44. int    pause = 0;
  45. Boolean waitForSignal = FALSE;
  46.  
  47. Option optionArray[] = {
  48.     {OPT_STRING, "o", (Address)&outFile,
  49.         "Output file name\n"},
  50.     {OPT_STRING, "p", (Address)&pdev,
  51.         "Name of the master pseudo device\n"},
  52.     {OPT_TRUE, "f", (Address)&flushCache,
  53.         "Flush cache before benchmark"},
  54.     {OPT_TRUE, "x", (Address)&clean,
  55.         "Turn off all tracing"},
  56.     {OPT_TRUE, "h", (Address)&histogram,
  57.         "Leave histograms on (ok with -x)"},
  58.     {OPT_TRUE, "S", (Address)&slave,
  59.         "Slave bench program"},
  60.     {OPT_INT, "M", (Address)&numClients,
  61.         "Master for -M (int) clients"},
  62.     {OPT_TRUE, "d", (Address)&dontSyncCache,
  63.         "Dont sync the cache when done"},
  64.     {OPT_TRUE, "s", (Address)&useSignals,
  65. "Use signals to rendevous the master and slave instead of pseudo-devices.\n"},
  66.     {OPT_INT, "P", (Address)&pause,
  67.         "Seconds to pause before get final stats"},
  68.     {OPT_REST, "c", (Address)&exec,
  69.         "(Follow with command to benchmark)"},
  70.     {OPT_TRUE, "w", (Address) &waitForSignal,
  71.         "Master waits for USR1 signal before starting slaves.\n"},
  72. };
  73. int numOptions = sizeof(optionArray) / sizeof(Option);
  74.  
  75. Fs_Stats fsStartStats, fsEndStats;
  76. Vm_Stat    vmStartStats, vmEndStats;
  77. Sys_DiskStats    diskStartStats[10], diskEndStats[10];
  78.  
  79. Time startTime, endTime;
  80. Sched_Instrument startSchedStats, endSchedStats;
  81. Net_EtherStats    netStartStats, netEndStats;
  82.  
  83. #ifdef spur
  84. MachStats startMachStats, endMachStats;
  85. #endif
  86.  
  87. #define NUM_PCBS    256
  88. Proc_ControlBlock pcbs1[NUM_PCBS];
  89. Proc_ControlBlock pcbs2[NUM_PCBS];
  90. Proc_PCBArgString argStrings1[NUM_PCBS];
  91. Proc_PCBArgString argStrings2[NUM_PCBS];
  92. int numPCB1, numPCB2;
  93.  
  94. extern void ServerSetup();
  95. extern void Serve();
  96.  
  97. extern void ClientSetup();
  98. extern void ClientDone();
  99.  
  100. extern void PrintTimes();
  101. extern void PrintIdleTime();
  102. extern void PrintFsStats();
  103. extern void PrintVmStats();
  104. extern void PrintDiskStats();
  105.  
  106. extern int errno;
  107.  
  108. Boolean    gotSig = FALSE;
  109. Boolean startClients = FALSE;
  110.  
  111. main(argc, argv)
  112.     int argc;
  113.     char *argv[];
  114. {
  115.     register ReturnStatus status = SUCCESS;
  116.     Proc_PID child;
  117.     Proc_ResUsage usage;
  118.     FILE *outStream;
  119.     int i;
  120.     ClientData serverData, clientData;
  121.     int    mastPID;
  122.     int    pidFD;
  123.  
  124.  
  125.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  126.     if (!exec && (numClients < 0)) {
  127.     fprintf(stderr, "Master: %s [-xfh] -M numSlaves\n", argv[0]);
  128.     fprintf(stderr, 
  129.         "Slave: %s [-xfh] -S -c commandPathName flags...\n", argv[0]);
  130.     Opt_PrintUsage(argv[0], optionArray, numOptions);
  131.     exit(1);
  132.     }
  133.     if ((numClients < 0) && waitForSignal) {
  134.     fprintf(stderr,"The -w flag can only be used with the -M flag.\n");
  135.     Opt_PrintUsage(argv[0], optionArray, numOptions);
  136.     exit(1);
  137.     }
  138.     if (waitForSignal) {
  139.     int HandleUSR1();
  140.     (void) signal(SIGUSR1, HandleUSR1);
  141.     }
  142.     if (clean) {
  143.     int newValue;
  144.     newValue = 0;
  145.     Fs_Command(FS_SET_CACHE_DEBUG, sizeof(int), (Address) &newValue);
  146.     newValue = 0;
  147.     Fs_Command(FS_SET_TRACING, sizeof(int), (Address) &newValue);
  148.     newValue = 0;
  149.     Fs_Command(FS_SET_RPC_DEBUG, sizeof(int), (Address) &newValue);
  150.     newValue = 0;
  151.     Fs_Command(FS_SET_RPC_TRACING, sizeof(int), (Address) &newValue);
  152.     if (!histogram) {
  153.         newValue = 0;
  154.         (void) Fs_Command(FS_SET_RPC_SERVER_HIST, sizeof(int),
  155.                 (Address) &newValue);
  156.         newValue = 0;
  157.         (void) Fs_Command(FS_SET_RPC_CLIENT_HIST, sizeof(int),
  158.                 (Address) &newValue);
  159.     }
  160.     }
  161.     if (flushCache) {
  162.     int numLockedBlocks = 0;
  163.     Fs_Command(FS_EMPTY_CACHE, sizeof(int), (Address) &numLockedBlocks);
  164.         if (numLockedBlocks > 0) {
  165.             fprintf(stderr, "Flush found %d locked blocks left\n",
  166.                                       numLockedBlocks);
  167.         }
  168.     }
  169.     outStream = fopen(outFile, "w+");
  170.     if (outStream == NULL) {
  171.     fprintf(stderr, "\"%s\": ", outFile);
  172.     Stat_PrintMsg(status, "Can't open");
  173.     exit(status);
  174.     }
  175.     /*
  176.      * Copy command line to output file.
  177.      */
  178.     fprintf(outStream, "%s ", argv[0]);
  179.     if (clean) {
  180.     fprintf(outStream, "-x ");
  181.     }
  182.     if (histogram) {
  183.     fprintf(outStream, "-h ");
  184.     }
  185.     if (flushCache) {
  186.     fprintf(outStream, "-f ");
  187.     }
  188.     if (clean) {
  189.     fprintf(outStream, "-x ");
  190.     }
  191.     for (i=1 ; i<argc ; i++) {
  192.     fprintf(outStream, "%s ", argv[i]);
  193.     }
  194.     fprintf(outStream, "\n");
  195.     if (useSignals) {
  196.     if (numClients > 0) {
  197.         int        bytesWritten;
  198.         Sig_Action    newAction, oldAction;
  199.         int        Handler();
  200.  
  201.         newAction.action = SIG_HANDLE_ACTION;
  202.         newAction.handler = Handler;
  203.         newAction.sigHoldMask = 0;
  204.         Sig_SetAction(30, &newAction, &oldAction);
  205.         /*
  206.          * Get our PID and store it in a file.
  207.          */
  208.         Proc_GetIDs(&mastPID, NULL, NULL, NULL);
  209.         pidFD = open("/tmp/db.pid", 
  210.                 O_WRONLY | O_CREAT | O_TRUNC,
  211.                 0666, &pidFD);
  212.         if (pidFD == NULL) {
  213.         fprintf(stderr,
  214.             "Master: Couldn't open pid file, status <%x>\n",
  215.             errno);
  216.         exit(errno);
  217.         }
  218.         bytesWritten = write(pidFD, &mastPID, sizeof(int));
  219.         while (!gotSig) {
  220.         Sig_Pause(0);
  221.         }
  222.         gotSig = FALSE;
  223.         printf("Got start signal\n");
  224.         fflush(stdout);
  225.     }
  226.     if (slave) {
  227.         int    bytesRead;
  228.         /*
  229.          * Read the master's pid out of the pid file and send him a 
  230.          * signal.
  231.          */
  232.         do {
  233.         pidFD = open("/tmp/db.pid", O_RDONLY, 0);
  234.         if (pidFD < 0) {
  235.             fprintf(stderr,
  236.         "Slave: Couldn't open pid file, status <%x>, pausing 5 seconds\n",
  237.             errno);
  238.             Sync_WaitTime(5, 0);
  239.             continue;
  240.         }
  241.         mastPID = 0;
  242.         bytesRead = read(pidFD, &mastPID, sizeof(int));
  243.         status = Sig_Send(30, mastPID, FALSE);
  244.         if (status == SUCCESS) {
  245.             /*
  246.              * Pause for one second to let the master receive
  247.              * our signal and gather stats.
  248.              */
  249.             Sync_WaitTime(1, 0);
  250.             break;
  251.         }
  252.         fprintf(stderr,
  253.         "Slave: couldn't signal parent, status <%x>, pausing 5 seconds\n",
  254.             status);
  255.         close(pidFD);
  256.         Sync_WaitTime(5, 0);
  257.         continue;
  258.         } while (TRUE);
  259.     }
  260.     } else {
  261.     /*
  262.      * Check for multi-program master/slave setup.
  263.      */
  264.     if (numClients > 0) {
  265.         ServerSetup(numClients, &serverData);
  266.         slave = FALSE;
  267.     }
  268.     if (slave) {
  269.         ClientSetup(&clientData);
  270.     }
  271.     }
  272.     /*
  273.      * Get first sample of filesystem stats, vm stats, time, and idle ticks.
  274.      */
  275.     status = Fs_Command(FS_RETURN_STATS, sizeof(Fs_Stats),
  276.             (Address) &fsStartStats);
  277.     if (status != SUCCESS) {
  278.     Stat_PrintMsg(status, "Error getting FS stats");
  279.     exit(status);
  280.     }
  281.     status = Sys_Stats(SYS_VM_STATS, 0, (Address) &vmStartStats);
  282.     if (status != SUCCESS) {
  283.     Stat_PrintMsg(status, "Error getting VM stats");
  284.     exit(status);
  285.     }
  286.     status = Sys_Stats(SYS_DISK_STATS, 10, diskStartStats);
  287.     if (status != SUCCESS) {
  288.     Stat_PrintMsg(status, "Error getting Disk stats");
  289.     exit(status);
  290.     }
  291.     /*
  292.      * Clear low and high water marks for the file system cache.
  293.      */
  294.     status = Vm_Cmd(VM_RESET_FS_STATS, 0);
  295.     if (status != SUCCESS) {
  296.     Stat_PrintMsg(status, "Error resetting fs low and high water marks\n");
  297.     }
  298.     status = Sys_Stats(SYS_NET_ETHER_STATS, 0, (Address) &netStartStats);
  299.     if (status != SUCCESS) {
  300.     Stat_PrintMsg(status, "Error getting NET stats");
  301.     exit(status);
  302.     }
  303.     /*
  304.      * Snapshot the process table so we can apportion CPU usage
  305.      * to various processes.
  306.      */
  307.     numPCB1 = GetProcTable(NUM_PCBS, pcbs1, argStrings1);
  308.  
  309.     status = Sys_GetTimeOfDay(&startTime, NULL, NULL);
  310.     if (status != SUCCESS) {
  311.     Stat_PrintMsg(status, "Error in Sys_GetTimeOfDay");
  312.     exit(status);
  313.     }
  314.     status = Sys_Stats(SYS_SCHED_STATS, 0, (Address) &startSchedStats);
  315.     if (status != SUCCESS) {
  316.     Stat_PrintMsg(status, "Error in Sys_Stats");
  317.     exit(status);
  318.     }
  319. #ifdef spur
  320.     status = InitMachStats( (Address) &startMachStats, MODE_PERF_COUNTER_OFF);
  321.     if (status != SUCCESS) {
  322.     Stat_PrintMsg(status, "Error in InitMachStats");
  323.         exit(status);
  324.     }
  325. #endif
  326.     if (slave || numClients < 0) {
  327.     status = Proc_Fork(FALSE, &child);
  328.     if (status == PROC_CHILD_PROC) {
  329.         /*
  330.          * Put ourselves in our own family.
  331.          */
  332.         (void) Proc_SetFamilyID(PROC_MY_PID, child);
  333.         (void) Ioc_SetOwner (0, child, IOC_OWNER_FAMILY);
  334.         /*
  335.          * Exec the program to benchmark.  Opt_Parse has left the command
  336.          * starting at argv[1], hence the following argv++.
  337.          */
  338.         argv++;
  339.         status = Proc_Exec(argv[0], argv, FALSE);
  340.         if (status != SUCCESS) {
  341.         fprintf(stderr,"Exec of \"%s\" failed",argv[0]);
  342.         Stat_PrintMsg(status, "");
  343.         fflush(stdout);
  344.         exit(status);
  345.         }
  346.     } else if (status == SUCCESS) {
  347.         /*
  348.          * Wait for the benchmark to complete.
  349.          */
  350.         status = Proc_Wait(0, NULL, TRUE, NULL,
  351.                   NULL, NULL, NULL, &usage);
  352.         if (status != SUCCESS) {
  353.         Stat_PrintMsg(status, "Error in Proc_Wait");
  354.         exit(status);
  355.         }
  356.         /*
  357.          * Take ending statistics and print user, system, and elapsed times.
  358.          */
  359. #ifdef spur
  360.         status = GetMachStats( (Address) &endMachStats);
  361.         if (status != SUCCESS) {
  362.         Stat_PrintMsg(status, "Error in GetMachStats");
  363.         exit(status);
  364.         };
  365. #endif
  366.         Sys_GetTimeOfDay(&endTime, NULL, NULL);
  367.         Sys_Stats(SYS_SCHED_STATS, 0, (Address) &endSchedStats);
  368.         Time_Subtract(endTime, startTime, &endTime);
  369.         PrintTimes(stderr, &usage, &endTime);
  370.         if (!dontSyncCache) {
  371.         Sys_Shutdown(SYS_WRITE_BACK, "");    /* sync cache */
  372.         }
  373.         if (slave) {
  374.         if (useSignals) {
  375.             status = Sig_Send(30, mastPID, FALSE);
  376.             if (status != SUCCESS) {
  377.             fprintf(stderr,
  378.                 "Slave: couldn't signal parent (2), status <%x>\n",
  379.                 status);
  380.             }
  381.         } else {
  382.             ClientDone(clientData);
  383.         }
  384.         }
  385.         numPCB2 = GetProcTable(NUM_PCBS, pcbs2, argStrings2);
  386.         Fs_Command(FS_RETURN_STATS, sizeof(Fs_Stats), (Address) &fsEndStats);
  387.         Sys_Stats(SYS_VM_STATS, 0, (Address) &vmEndStats);
  388.         Sys_Stats(SYS_DISK_STATS, 10, diskEndStats);
  389.         Sys_Stats(SYS_NET_ETHER_STATS, 0, (Address) &netEndStats);
  390.         /*
  391.          * Print FS statistics.
  392.          */
  393.         PrintTimes(outStream, &usage, &endTime);
  394.         PrintIdleTime(outStream, &startSchedStats, &endSchedStats, &endTime);
  395.         PrintFsStats(outStream, &fsStartStats, &fsEndStats, TRUE);
  396.         PrintDiskStats(outStream, diskStartStats, diskEndStats);
  397.         /*
  398.          * Print VM statistics.
  399.          */
  400.         PrintVmStats(outStream, &vmStartStats, &vmEndStats);
  401.         /*
  402.          * Print network statistics.
  403.          */
  404.         fprintf(outStream,
  405.             "Network stats: Bytes received %d bytes sent %d\n",
  406.             netEndStats.bytesReceived - netStartStats.bytesReceived,
  407.             netEndStats.bytesSent - netStartStats.bytesSent);
  408.         /*
  409.          * Print out process info.
  410.          */
  411.         PrintProcStats(outStream, numPCB1, pcbs1, argStrings1,
  412.                       numPCB2, pcbs2, argStrings2);
  413. #ifdef spur
  414.         /*
  415.          * Print Machine dependent stats
  416.          */
  417.         PrintMachStats(outStream, &startMachStats, &endMachStats);
  418. #endif
  419.     } else {
  420.         Stat_PrintMsg(status, "Error in Proc_Fork");
  421.     }
  422.     } else {
  423.     if (useSignals) {
  424.         while (!gotSig) { 
  425.         Sig_Pause(0);
  426.         }
  427.         printf("Got end signal\n");
  428.         fflush(stdout);
  429.     } else {
  430.         Serve(serverData);
  431.     }
  432.     if (pause) {
  433.         sleep(pause);
  434.     }
  435. #ifdef spur
  436.     /*
  437.      * Take ending statistics and print user, system, and elapsed times.
  438.      */
  439.     status = GetMachStats( (Address) &endMachStats);
  440.     if (status != SUCCESS) {
  441.         Stat_PrintMsg(status, "Error in GetMachStats");
  442.         exit(status);
  443.     };
  444. #endif
  445.     Sys_GetTimeOfDay(&endTime, NULL, NULL);
  446.     Sys_Stats(SYS_SCHED_STATS, 0, (Address) &endSchedStats);
  447.     Time_Subtract(endTime, startTime, &endTime);
  448.     PrintTimes(stderr, &usage, &endTime);
  449.  
  450.     if (!dontSyncCache) {
  451.         Sys_Shutdown(SYS_WRITE_BACK, "");    /* sync cache */
  452.     }
  453.     Fs_Command(FS_RETURN_STATS, sizeof(Fs_Stats), (Address) &fsEndStats);
  454.     Sys_Stats(SYS_VM_STATS, 0, (Address) &vmEndStats);
  455.     Sys_Stats(SYS_DISK_STATS, 10, diskEndStats);
  456.     Sys_Stats(SYS_NET_ETHER_STATS, 0, (Address) &netEndStats);
  457.     /*
  458.      * Print FS statistics.
  459.      */
  460.     PrintTimes(outStream, &usage, &endTime);
  461.     PrintIdleTime(outStream, &startSchedStats, &endSchedStats, &endTime);
  462.     PrintFsStats(outStream, &fsStartStats, &fsEndStats, TRUE);
  463.     PrintDiskStats(outStream, diskStartStats, diskEndStats);
  464.     /*
  465.      * Print VM statitistics.
  466.      */
  467.     PrintVmStats(outStream, &vmStartStats, &vmEndStats);
  468.     /*
  469.      * Print network statistics.
  470.      */
  471.     fprintf(outStream,
  472.             "Network stats: Bytes received %d bytes sent %d\n",
  473.             netEndStats.bytesReceived - netStartStats.bytesReceived,
  474.             netEndStats.bytesSent - netStartStats.bytesSent);
  475. #ifdef spur
  476.     /*
  477.     ** Print Machine dependent stats
  478.     */
  479.     PrintMachStats(outStream, &startMachStats, &endMachStats);
  480. #endif
  481.     }
  482.     exit(status);
  483. }
  484.  
  485. int
  486. Handler()
  487. {
  488.     gotSig = TRUE;
  489. }
  490.  
  491. int
  492. HandleUSR1()
  493. {
  494.     startClients = TRUE;
  495. }
  496.